#include "stdafx.h"

#include "dll_inject.h"
#include "functions.h"
#include "logger.h"
#include "storage_manager.h"
#include "var_init_once.h"

extern HINSTANCE g_hDllInst;

namespace {

#define PRE_X32SHELLCODE_ARGS_3_TO_1 \
    "\x58"         /* pop eax   */   \
    "\x59"         /* pop ecx   */   \
    "\x83\xC4\x08" /* add esp,8 */   \
    "\x51"         /* push ecx  */   \
    "\x50"         /* push eax  */

#define PRE_X32SHELLCODE_VIRTUAL_FREE                           \
    "\xFF\x74\x24\x04"         /* push dword ptr ss:[esp+4]  */ \
    "\xE8\x1E\x00\x00\x00"     /* call $+1E                  */ \
    "\x85\xC0"                 /* test eax,eax               */ \
    "\x75\x03"                 /* jne $+3                    */ \
    "\xC2\x04\x00"             /* ret 4                      */ \
    "\x59"                     /* pop ecx                    */ \
    "\x5A"                     /* pop edx                    */ \
    "\x68\x00\x80\x00\x00"     /* push 8000                  */ \
    "\x6A\x00"                 /* push 0                     */ \
    "\xE8\x00\x00\x00\x00"     /* call $                     */ \
    "\x66\x81\x24\x24\x00\xF0" /* and word ptr ss:[esp],F000 */ \
    "\x51"                     /* push ecx                   */ \
    "\xFF\xE0"                 /* jmp eax                    */

// The 32-bit InjectShellcode function from the project in the inject_shellcode
// subfolder.
const BYTE x32APCShellcode[] =
    PRE_X32SHELLCODE_ARGS_3_TO_1 PRE_X32SHELLCODE_VIRTUAL_FREE
    "\x55\x8B\xEC\x81\xEC\xBC\x01\x00\x00\x56\x64\x8B\x35\x30\x00\x00\x00\x89"
    "\xB5\x0C\xFF\xFF\xFF\x83\x7E\x0C\x00\x75\x09\x33\xC0\x5E\x8B\xE5\x5D\xC2"
    "\x04\x00\x8D\x85\x7C\xFF\xFF\xFF\xC7\x45\x8C\x4B\x45\x52\x4E\x89\x85\x64"
    "\xFE\xFF\xFF\x33\xC9\x8D\x85\x4C\xFF\xFF\xFF\xC7\x45\x90\x45\x4C\x33\x32"
    "\x89\x85\x68\xFE\xFF\xFF\x8D\x45\x98\x89\x85\x6C\xFE\xFF\xFF\x8D\x45\xA4"
    "\x89\x85\x70\xFE\xFF\xFF\x8D\x85\x6C\xFF\xFF\xFF\x89\x85\x74\xFE\xFF\xFF"
    "\x8D\x85\x24\xFF\xFF\xFF\x89\x85\x78\xFE\xFF\xFF\x8D\x45\xB0\x89\x85\x7C"
    "\xFE\xFF\xFF\x8D\x85\x10\xFF\xFF\xFF\x89\x85\x80\xFE\xFF\xFF\x8D\x85\xE8"
    "\xFE\xFF\xFF\x89\x85\x44\xFE\xFF\xFF\x8D\x85\xEC\xFE\xFF\xFF\x89\x85\x48"
    "\xFE\xFF\xFF\x8D\x85\xF0\xFE\xFF\xFF\x89\x85\x4C\xFE\xFF\xFF\x8D\x45\xD4"
    "\x89\x85\x50\xFE\xFF\xFF\x8D\x85\xFC\xFE\xFF\xFF\x89\x85\x54\xFE\xFF\xFF"
    "\x8D\x45\xE4\x89\x85\x58\xFE\xFF\xFF\x8D\x85\xF8\xFE\xFF\xFF\x53\x33\xDB"
    "\x89\x85\x5C\xFE\xFF\xFF\x8D\x85\xF4\xFE\xFF\xFF\xC7\x45\x94\x2E\x44\x4C"
    "\x4C\xC7\x85\x7C\xFF\xFF\xFF\x4C\x6F\x61\x64\xC7\x45\x80\x4C\x69\x62\x72"
    "\xC7\x45\x84\x61\x72\x79\x57\xC6\x45\x88\x00\xC7\x85\x4C\xFF\xFF\xFF\x47"
    "\x65\x74\x50\xC7\x85\x50\xFF\xFF\xFF\x72\x6F\x63\x41\xC7\x85\x54\xFF\xFF"
    "\xFF\x64\x64\x72\x65\x66\xC7\x85\x58\xFF\xFF\xFF\x73\x73\xC6\x85\x5A\xFF"
    "\xFF\xFF\x00\xC7\x45\x98\x46\x72\x65\x65\xC7\x45\x9C\x4C\x69\x62\x72\xC7"
    "\x45\xA0\x61\x72\x79\x00\xC7\x45\xA4\x56\x69\x72\x74\xC7\x45\xA8\x75\x61"
    "\x6C\x46\xC7\x45\xAC\x72\x65\x65\x00\xC7\x85\x6C\xFF\xFF\xFF\x47\x65\x74"
    "\x4C\xC7\x85\x70\xFF\xFF\xFF\x61\x73\x74\x45\xC7\x85\x74\xFF\xFF\xFF\x72"
    "\x72\x6F\x72\xC6\x85\x78\xFF\xFF\xFF\x00\xC7\x85\x24\xFF\xFF\xFF\x4F\x75"
    "\x74\x70\xC7\x85\x28\xFF\xFF\xFF\x75\x74\x44\x65\xC7\x85\x2C\xFF\xFF\xFF"
    "\x62\x75\x67\x53\xC7\x85\x30\xFF\xFF\xFF\x74\x72\x69\x6E\x66\xC7\x85\x34"
    "\xFF\xFF\xFF\x67\x41\xC6\x85\x36\xFF\xFF\xFF\x00\xC7\x45\xB0\x43\x6C\x6F"
    "\x73\xC7\x45\xB4\x65\x48\x61\x6E\xC7\x45\xB8\x64\x6C\x65\x00\xC7\x85\x10"
    "\xFF\xFF\xFF\x53\x65\x74\x54\xC7\x85\x14\xFF\xFF\xFF\x68\x72\x65\x61\xC7"
    "\x85\x18\xFF\xFF\xFF\x64\x45\x72\x72\xC7\x85\x1C\xFF\xFF\xFF\x6F\x72\x4D"
    "\x6F\x66\xC7\x85\x20\xFF\xFF\xFF\x64\x65\xC6\x85\x22\xFF\xFF\xFF\x00\xC7"
    "\x85\xE8\xFE\xFF\xFF\x00\x00\x00\x00\xC7\x85\xEC\xFE\xFF\xFF\x00\x00\x00"
    "\x00\xC7\x85\xF0\xFE\xFF\xFF\x00\x00\x00\x00\xC7\x45\xD4\x00\x00\x00\x00"
    "\xC7\x85\xFC\xFE\xFF\xFF\x00\x00\x00\x00\x89\x4D\xE4\x89\x8D\xF8\xFE\xFF"
    "\xFF\x89\x5D\xDC\x89\x9D\xF4\xFE\xFF\xFF\x89\x85\x60\xFE\xFF\xFF\x8D\x85"
    "\x64\xFE\xFF\xFF\xC7\x85\x98\xFE\xFF\xFF\x0C\x00\x00\x00\x89\x85\x9C\xFE"
    "\xFF\xFF\x8D\x95\x04\xFF\xFF\xFF\x8D\x85\x44\xFE\xFF\xFF\x89\x95\x84\xFE"
    "\xFF\xFF\x89\x85\xA0\xFE\xFF\xFF\x8D\x95\x00\xFF\xFF\xFF\x33\xC0\x89\x95"
    "\x88\xFE\xFF\xFF\x8B\x55\x08\x8D\x5D\x8C\x89\x85\xA8\xFE\xFF\xFF\x89\x85"
    "\xAC\xFE\xFF\xFF\x89\x85\xB0\xFE\xFF\xFF\x89\x85\xB4\xFE\xFF\xFF\x89\x85"
    "\xB8\xFE\xFF\xFF\x89\x85\xBC\xFE\xFF\xFF\x89\x85\xC0\xFE\xFF\xFF\x89\x85"
    "\xC4\xFE\xFF\xFF\x89\x85\xC8\xFE\xFF\xFF\x89\x85\xCC\xFE\xFF\xFF\x88\x85"
    "\x48\xFF\xFF\xFF\x8D\x85\x38\xFF\xFF\xFF\x89\x85\x8C\xFE\xFF\xFF\x8D\x85"
    "\x5C\xFF\xFF\xFF\x89\x85\x90\xFE\xFF\xFF\x33\xC0\x89\x9D\x94\xFE\xFF\xFF"
    "\xC7\x85\xA4\xFE\xFF\xFF\x08\x00\x00\x00\xC7\x45\xC8\x4E\x54\x44\x4C\xC7"
    "\x45\xCC\x4C\x2E\x44\x4C\xC6\x45\xD0\x4C\xC7\x85\x38\xFF\xFF\xFF\x4E\x74"
    "\x51\x75\xC7\x85\x3C\xFF\xFF\xFF\x65\x75\x65\x41\xC7\x85\x40\xFF\xFF\xFF"
    "\x70\x63\x54\x68\xC7\x85\x44\xFF\xFF\xFF\x72\x65\x61\x64\xC7\x85\x5C\xFF"
    "\xFF\xFF\x4E\x74\x41\x6C\xC7\x85\x60\xFF\xFF\xFF\x65\x72\x74\x54\xC7\x85"
    "\x64\xFF\xFF\xFF\x68\x72\x65\x61\x66\xC7\x85\x68\xFF\xFF\xFF\x64\x00\x89"
    "\x85\x04\xFF\xFF\xFF\x89\x85\x00\xFF\xFF\xFF\x39\x42\x04\x74\x3B\xF6\x46"
    "\x28\x02\x74\x35\x8D\x55\xC8\xC7\x85\xAC\xFE\xFF\xFF\x09\x00\x00\x00\x89"
    "\x95\xA8\xFE\xFF\xFF\x8D\x95\x8C\xFE\xFF\xFF\x89\x95\xB0\xFE\xFF\xFF\x8D"
    "\x95\x84\xFE\xFF\xFF\x89\x95\xB4\xFE\xFF\xFF\xC7\x85\xB8\xFE\xFF\xFF\x02"
    "\x00\x00\x00\x57\x8B\x7E\x0C\x32\xD2\x83\xC7\x0C\x89\x7D\xD8\x8B\x3F\x3B"
    "\x7D\xD8\x0F\x84\xD2\x00\x00\x00\x8B\xCF\x32\xD2\x8B\x3F\x89\x4D\xE0\x89"
    "\xBD\xD8\xFE\xFF\xFF\x66\x8B\x41\x2C\x33\xC9\x66\xD1\xE8\x0F\xB7\xF8\x89"
    "\x4D\xE8\x85\xDB\x0F\x84\x8B\x00\x00\x00\x8D\x9D\x94\xFE\xFF\xFF\x89\x9D"
    "\x08\xFF\xFF\xFF\x83\x7B\x10\x00\x74\x55\x3B\x7B\x04\x75\x50\x33\xC0\x33"
    "\xF6\x66\x3B\xC7\x73\x3E\x8B\x1B\x8D\x9B\x00\x00\x00\x00\x8B\x55\xE0\x0F"
    "\xB7\xCE\x8B\x42\x30\x0F\xB7\x14\x48\x8D\x42\x9F\x66\x83\xF8\x19\x77\x06"
    "\x81\xC2\xE0\xFF\x00\x00\x0F\xBE\x0C\x19\x0F\xB7\xC2\x3B\xC1\x75\x06\x46"
    "\x66\x3B\xF7\x72\xD3\x8B\x9D\x08\xFF\xFF\xFF\x8B\x4D\xE8\x66\x3B\xF7\x0F"
    "\x84\xD8\x00\x00\x00\x41\x8D\x9D\x94\xFE\xFF\xFF\x32\xD2\x89\x4D\xE8\x8D"
    "\x04\x89\x83\x3C\x83\x00\x8D\x1C\x83\x89\x9D\x08\xFF\xFF\xFF\x75\x87\x8B"
    "\x9D\x94\xFE\xFF\xFF\x8B\xBD\xD8\xFE\xFF\xFF\x3B\x7D\xD8\x0F\x85\x40\xFF"
    "\xFF\xFF\x8B\x85\xF4\xFE\xFF\xFF\x8B\x4D\xE4\x89\x45\xDC\x8B\x85\x04\xFF"
    "\xFF\xFF\x8B\x7D\x08\x83\x7F\x04\x00\x8B\x37\x0F\x84\x1B\x02\x00\x00\x8B"
    "\x9D\x0C\xFF\xFF\xFF\xF6\x43\x28\x02\x0F\x84\x0B\x02\x00\x00\x85\xC9\x74"
    "\x2D\x83\xFE\x02\x7C\x28\x8D\x45\xF0\xC7\x45\xF0\x5B\x57\x48\x5D\x50\xC7"
    "\x45\xF4\x20\x41\x50\x43\xC7\x45\xF8\x20\x52\x45\x0A\xC6\x45\xFC\x00\xFF"
    "\xD1\x8B\x4D\xE4\x8B\x85\x04\xFF\xFF\xFF\x32\xDB\x85\xC0\x0F\x84\x8B\x01"
    "\x00\x00\x83\xBD\x00\xFF\xFF\xFF\x00\x0F\x84\x7E\x01\x00\x00\x6A\x00\x6A"
    "\x00\x57\xFF\x77\x20\x6A\xFE\xFF\xD0\x85\xC0\x0F\x88\x5F\x01\x00\x00\x6A"
    "\xFE\xB3\x01\xFF\x95\x00\xFF\xFF\xFF\x85\xC0\x0F\x99\xC0\xFE\xC8\x24\x04"
    "\xE9\x49\x01\x00\x00\x32\xD2\x85\xDB\x0F\x84\x3C\xFF\xFF\xFF\x8B\x45\xE0"
    "\x8B\x70\x18\x89\x75\xE0\x8B\x46\x3C\x8B\x54\x30\x78\x8B\x44\x32\x20\x03"
    "\xD6\x03\xC6\x89\x95\xD4\xFE\xFF\xFF\x89\x85\xE4\xFE\xFF\xFF\x8B\x4A\x24"
    "\x8B\x7A\x18\x03\xCE\x89\x4D\xE8\x8B\x4B\x10\x89\x7D\xDC\x85\xFF\x74\x61"
    "\x8B\x38\x8B\xD1\x03\xFE\x33\xF6\x85\xC9\x74\x32\x8B\x43\x08\x8A\x2F\xEB"
    "\x03\x8D\x49\x00\x8B\x14\xB0\x8A\x0A\x3A\xCD\x75\x17\x8B\xC7\x2B\xD7\x8D"
    "\x49\x00\x84\xC9\x74\x6C\x8A\x4C\x02\x01\x40\x3A\x08\x74\xF3\x8B\x43\x08"
    "\x8B\x53\x10\x46\x3B\xF2\x72\xD8\x8B\x75\xE0\x8B\x85\xE4\xFE\xFF\xFF\x8B"
    "\xCA\x8B\x7D\xDC\x83\xC0\x04\x83\x45\xE8\x02\x4F\x89\x85\xE4\xFE\xFF\xFF"
    "\x89\x7D\xDC\x85\xD2\x75\x9B\x8B\x9D\x94\xFE\xFF\xFF\x33\xC9\xB2\x01\x85"
    "\xDB\x0F\x84\xA5\xFE\xFF\xFF\x33\xC0\x90\x83\xBC\x05\xA4\xFE\xFF\xFF\x00"
    "\x77\x7D\x41\x8D\x04\x89\xC1\xE0\x02\x83\xBC\x05\x94\xFE\xFF\xFF\x00\x75"
    "\xE5\xE9\x82\xFE\xFF\xFF\x8B\x4B\x10\x8B\x43\x0C\x8B\x3C\xB0\x8D\x04\xB0"
    "\x89\x85\xD0\xFE\xFF\xFF\x8D\x51\xFF\x3B\xF2\x73\x22\x8B\x43\x08\x8B\x5B"
    "\x08\x8B\x44\x88\xFC\x89\x04\xB3\x8B\x9D\x08\xFF\xFF\xFF\x8B\x43\x0C\x8B"
    "\x44\x88\xFC\x8B\x8D\xD0\xFE\xFF\xFF\x89\x01\x8B\x75\xE0\x89\x53\x10\x85"
    "\xFF\x0F\x84\x62\xFF\xFF\xFF\x8B\x45\xE8\x0F\xB7\x08\x8B\x85\xD4\xFE\xFF"
    "\xFF\x8B\x40\x1C\x8D\x04\x88\x8B\x04\x30\x03\xC6\x89\x07\xE9\x44\xFF\xFF"
    "\xFF\x32\xD2\xE9\x05\xFE\xFF\xFF\xB0\x02\x84\xC0\x74\x36\x8B\x4D\xE4\xEB"
    "\x02\xB0\x01\x85\xC9\x74\x2B\x83\xFE\x01\x7C\x26\x04\x30\xC7\x45\xF0\x5B"
    "\x57\x48\x5D\x88\x45\xFC\x8D\x45\xF0\x50\xC7\x45\xF4\x20\x41\x50\x43\xC7"
    "\x45\xF8\x20\x45\x52\x52\x66\xC7\x45\xFD\x0A\x00\xFF\xD1\x33\xC0\x84\xDB"
    "\x5F\x0F\x95\xC0\x48\x23\x45\xD4\x5B\x5E\x8B\xE5\x5D\xC2\x04\x00\x84\xD2"
    "\x75\x37\x85\xC9\x0F\x84\x68\x02\x00\x00\x83\xFE\x01\x0F\x8C\x5F\x02\x00"
    "\x00\x8D\x45\xF4\xC7\x45\xF4\x5B\x57\x48\x5D\x50\xC7\x45\xF8\x20\x45\x58"
    "\x50\x66\xC7\x45\xFC\x0A\x00\xFF\xD1\x8B\x45\xD4\x5F\x5B\x5E\x8B\xE5\x5D"
    "\xC2\x04\x00\x8D\x85\xDC\xFE\xFF\xFF\xC7\x45\xBC\x49\x6E\x6A\x65\x50\x6A"
    "\x01\xC7\x45\xC0\x63\x74\x49\x6E\x33\xFF\x66\xC7\x45\xC4\x69\x74\x33\xDB"
    "\xC6\x45\xC6\x00\xC7\x45\xE8\x00\x00\x00\x00\xFF\x55\xDC\x83\xFE\x02\x7C"
    "\x18\x8D\x45\xF4\xC7\x45\xF4\x5B\x57\x48\x5D\x50\xC7\x45\xF8\x20\x4C\x4C"
    "\x0A\x88\x5D\xFC\xFF\x55\xE4\x8B\x45\x08\x8B\x8D\xE8\xFE\xFF\xFF\x83\xC0"
    "\x28\x50\xFF\xD1\x89\x45\xD8\x85\xC0\x0F\x84\xC5\x00\x00\x00\x83\xFE\x02"
    "\x7C\x1B\x8D\x45\xF4\xC7\x45\xF4\x5B\x57\x48\x5D\x50\xC7\x45\xF8\x20\x47"
    "\x50\x41\x66\xC7\x45\xFC\x0A\x00\xFF\x55\xE4\x8B\x85\xEC\xFE\xFF\xFF\x8D"
    "\x4D\xBC\x51\xFF\x75\xD8\xFF\xD0\x89\x85\x0C\xFF\xFF\xFF\x85\xC0\x74\x71"
    "\x83\xFE\x02\x7C\x58\x8D\x45\xF4\xC7\x45\xF4\x5B\x57\x48\x5D\x50\xC7\x45"
    "\xF8\x20\x49\x49\x0A\x88\x5D\xFC\xFF\x55\xE4\xFF\x75\x08\xC7\x45\xE8\x01"
    "\x00\x00\x00\xFF\x95\x0C\xFF\xFF\xFF\x8B\xF8\xC7\x45\xF4\x5B\x57\x48\x5D"
    "\x83\xC4\x04\xC7\x45\xF8\x20\x49\x49\x3A\x85\xFF\xC6\x45\xFC\x20\x66\xC7"
    "\x45\xFE\x0A\x00\x0F\x95\xC0\x04\x30\x88\x45\xFD\x8D\x45\xF4\x50\xFF\x55"
    "\xE4\xEB\x1C\x8B\x55\x08\x52\xC7\x45\xE8\x01\x00\x00\x00\xFF\xD0\x83\xC4"
    "\x04\x8B\xF8\xEB\x08\xFF\x95\xFC\xFE\xFF\xFF\x8B\xD8\xFF\x75\xD8\xFF\x95"
    "\xF0\xFE\xFF\xFF\x85\xFF\x0F\x85\x02\x01\x00\x00\xEB\x08\xFF\x95\xFC\xFE"
    "\xFF\xFF\x8B\xD8\x8B\x7D\x08\x8B\x47\x18\x85\xC0\x74\x07\x50\xFF\x95\xF8"
    "\xFE\xFF\xFF\xFF\x77\x10\xFF\x95\xF8\xFE\xFF\xFF\x83\x7D\xE8\x00\x0F\x85"
    "\xD4\x00\x00\x00\x83\xFE\x01\x0F\x8C\xCB\x00\x00\x00\x8B\xCB\xC7\x45\xEC"
    "\x5B\x57\x48\x5D\x83\xE1\x0F\xC7\x45\xF0\x20\x45\x52\x52\x83\xF9\x0A\x66"
    "\xC7\x45\xF4\x3A\x20\x66\xC7\x45\xFE\x0A\x00\x1A\xC0\x80\xC1\x37\x24\xF9"
    "\xC1\xEB\x04\x02\xC1\x8B\xCB\x88\x45\xFD\x83\xE1\x0F\x83\xF9\x0A\x1A\xC0"
    "\xC1\xEB\x04\x24\xF9\x04\x37\x02\xC1\x8B\xCB\x88\x45\xFC\x83\xE1\x0F\x83"
    "\xF9\x0A\x1A\xC0\xC1\xEB\x04\x24\xF9\x04\x37\x02\xC1\x8B\xCB\x88\x45\xFB"
    "\x83\xE1\x0F\x83\xF9\x0A\x1A\xC0\xC1\xEB\x04\x24\xF9\x04\x37\x02\xC1\x8B"
    "\xCB\x88\x45\xFA\x83\xE1\x0F\x83\xF9\x0A\x1A\xC0\xC1\xEB\x04\x24\xF9\x04"
    "\x37\x02\xC1\x8B\xCB\x88\x45\xF9\x83\xE1\x0F\x83\xF9\x0A\x1A\xC0\xC1\xEB"
    "\x04\x24\xF9\x04\x37\x02\xC1\x8B\xCB\x88\x45\xF8\x83\xE1\x0F\x83\xF9\x0A"
    "\x1A\xC0\x80\xC1\x37\x24\xF9\xC1\xEB\x04\x02\xC1\x83\xFB\x0A\x88\x45\xF7"
    "\x1A\xC0\x24\xF9\x04\x37\x02\xC3\x88\x45\xF6\x8D\x45\xEC\x50\xFF\x55\xE4"
    "\x6A\x00\xFF\xB5\xDC\xFE\xFF\xFF\xFF\x95\xF4\xFE\xFF\xFF\x8B\x45\xD4\x5F"
    "\x5B\x5E\x8B\xE5\x5D\xC2\x04\x00";

constexpr size_t x32APCShellcodeSize = sizeof(x32APCShellcode) - 1;

const BYTE* x32Shellcode =
    x32APCShellcode + sizeof(PRE_X32SHELLCODE_ARGS_3_TO_1) - 1;
constexpr size_t x32ShellcodeSize =
    (sizeof(x32APCShellcode) - 1) - (sizeof(PRE_X32SHELLCODE_ARGS_3_TO_1) - 1);

#define PRE_X64SHELLCODE_VIRTUAL_FREE                             \
    "\x48\x83\xEC\x28"             /* sub rsp,28               */ \
    "\xE8\x20\x00\x00\x00"         /* call $+20                */ \
    "\x48\x83\xC4\x28"             /* add rsp,28               */ \
    "\x48\x85\xC0"                 /* test rax,rax             */ \
    "\x75\x01"                     /* jne $+1                  */ \
    "\xC3"                         /* ret                      */ \
    "\x48\x8D\x0D\x00\x00\x00\x00" /* lea rcx,qword ptr ds:[$] */ \
    "\x66\x81\xE1\x00\xF0"         /* and cx,F000              */ \
    "\x33\xD2"                     /* xor edx,edx              */ \
    "\x41\xB8\x00\x80\x00\x00"     /* mov r8d,8000             */ \
    "\xFF\xE0"                     /* jmp rax                  */

// The 64-bit InjectShellcode function from the project in the inject_shellcode
// subfolder.
const BYTE x64Shellcode[] = PRE_X64SHELLCODE_VIRTUAL_FREE
    "\x48\x89\x4C\x24\x08\x55\x41\x55\x48\x8D\xAC\x24\x18\xFE\xFF\xFF\x48\x81"
    "\xEC\xE8\x02\x00\x00\x4C\x8B\xE9\x65\x48\x8B\x0C\x25\x60\x00\x00\x00\x48"
    "\x89\x4C\x24\x30\x48\x83\x79\x18\x00\x75\x0D\x33\xC0\x48\x81\xC4\xE8\x02"
    "\x00\x00\x41\x5D\x5D\xC3\xC7\x45\x98\x4B\x45\x52\x4E\x48\x8D\x45\xA8\xC7"
    "\x45\x9C\x45\x4C\x33\x32\xC7\x45\xA0\x2E\x44\x4C\x4C\xC7\x45\xA8\x4C\x6F"
    "\x61\x64\xC7\x45\xAC\x4C\x69\x62\x72\xC7\x45\xB0\x61\x72\x79\x57\xC6\x45"
    "\xB4\x00\xC7\x45\xD8\x47\x65\x74\x50\xC7\x45\xDC\x72\x6F\x63\x41\xC7\x45"
    "\xE0\x64\x64\x72\x65\x66\xC7\x45\xE4\x73\x73\xC6\x45\xE6\x00\xC7\x44\x24"
    "\x68\x46\x72\x65\x65\xC7\x44\x24\x6C\x4C\x69\x62\x72\xC7\x44\x24\x70\x61"
    "\x72\x79\x00\xC7\x44\x24\x78\x56\x69\x72\x74\xC7\x44\x24\x7C\x75\x61\x6C"
    "\x46\xC7\x45\x80\x72\x65\x65\x00\xC7\x45\xB8\x47\x65\x74\x4C\xC7\x45\xBC"
    "\x61\x73\x74\x45\xC7\x45\xC0\x72\x72\x6F\x72\xC6\x45\xC4\x00\xC6\x45\x00"
    "\x4F\xC6\x45\x01\x75\xC6\x45\x02\x74\xC6\x45\x03\x70\xC6\x45\x04\x75\xC6"
    "\x45\x05\x74\xC6\x45\x06\x44\xC6\x45\x07\x65\xC6\x45\x08\x62\xC6\x45\x09"
    "\x75\xC6\x45\x0A\x67\xC6\x45\x0B\x53\xC6\x45\x0C\x74\xC6\x45\x0D\x72\xC6"
    "\x45\x0E\x69\xC6\x45\x0F\x6E\xC6\x45\x10\x67\xC6\x45\x11\x41\xC6\x45\x12"
    "\x00\xC7\x45\x88\x43\x6C\x6F\x73\xC7\x45\x8C\x65\x48\x61\x6E\xC7\x45\x90"
    "\x64\x6C\x65\x00\xC6\x45\x18\x53\xC6\x45\x19\x65\xC6\x45\x1A\x74\xC6\x45"
    "\x1B\x54\xC6\x45\x1C\x68\xC6\x45\x1D\x72\xC6\x45\x1E\x65\xC6\x45\x1F\x61"
    "\xC6\x45\x20\x64\xC6\x45\x21\x45\xC6\x45\x22\x72\xC6\x45\x23\x72\x48\x89"
    "\x85\x30\x01\x00\x00\x48\x8D\x45\xD8\xC6\x45\x24\x6F\x48\x89\x85\x38\x01"
    "\x00\x00\x48\x8D\x44\x24\x68\xC6\x45\x25\x72\x48\x89\x85\x40\x01\x00\x00"
    "\x48\x8D\x44\x24\x78\xC6\x45\x26\x4D\x48\x89\x85\x48\x01\x00\x00\x48\x8D"
    "\x45\xB8\xC6\x45\x27\x6F\x48\x89\x9C\x24\xE0\x02\x00\x00\x48\x89\x85\x50"
    "\x01\x00\x00\x48\x8D\x45\x00\xC6\x45\x28\x64\x48\x89\xBC\x24\xD0\x02\x00"
    "\x00\x48\x89\x85\x58\x01\x00\x00\x48\x8D\x45\x88\xC6\x45\x29\x65\x4C\x89"
    "\xA4\x24\xC8\x02\x00\x00\xC6\x45\x2A\x00\x4C\x89\xBC\x24\xB8\x02\x00\x00"
    "\x48\x89\x85\x60\x01\x00\x00\xC7\x44\x24\x48\x4E\x54\x44\x4C\x48\x8D\x55"
    "\x60\x48\x89\x95\x70\x01\x00\x00\x48\x8D\x45\x18\x48\x89\x85\x68\x01\x00"
    "\x00\x48\x8D\x55\x68\x48\x89\x95\x78\x01\x00\x00\x4C\x8D\x7D\x98\xC7\x44"
    "\x24\x4C\x4C\x2E\x44\x4C\x48\x8D\x55\x70\x48\x89\x95\x80\x01\x00\x00\x45"
    "\x33\xE4\x48\x8D\x55\x30\x4C\x89\x65\x60\x0F\x57\xC0\x48\x89\x95\x88\x01"
    "\x00\x00\x48\x8D\x55\x48\x4C\x89\x65\x68\x41\x8B\xC4\x48\x89\x95\x90\x01"
    "\x00\x00\x48\x8D\x95\x10\x02\x00\x00\x4C\x89\x65\x70\x45\x8B\xC4\x48\x89"
    "\x95\x98\x01\x00\x00\x48\x8D\x55\x50\x4C\x89\x65\x30\x45\x8B\xD4\x48\x89"
    "\x95\xA0\x01\x00\x00\x48\x8D\x55\x58\x4C\x89\x65\x48\x48\x89\x95\xA8\x01"
    "\x00\x00\x48\x8D\x95\x30\x01\x00\x00\x48\x89\x85\x10\x02\x00\x00\x4C\x89"
    "\x65\x50\x4C\x89\x65\x58\xC6\x44\x24\x50\x4C\xC6\x45\xE8\x4E\xC6\x45\xE9"
    "\x74\xC6\x45\xEA\x51\xC6\x45\xEB\x75\xC6\x45\xEC\x65\xC6\x45\xED\x75\xC6"
    "\x45\xEE\x65\xC6\x45\xEF\x41\xC6\x45\xF0\x70\xC6\x45\xF1\x63\xC6\x45\xF2"
    "\x54\x48\x89\x95\xC0\x00\x00\x00\x48\x8D\x95\x70\x01\x00\x00\xC6\x45\xF3"
    "\x68\x48\x89\x95\xC8\x00\x00\x00\x48\x8D\x55\xE8\xC6\x45\xF4\x72\x48\x89"
    "\x95\x88\x00\x00\x00\x48\x8D\x55\xC8\xC6\x45\xF5\x65\x48\x89\x95\x90\x00"
    "\x00\x00\x48\x8D\x55\x38\xC6\x45\xF6\x61\x48\x89\x95\x98\x00\x00\x00\x48"
    "\x8D\x55\x40\xC6\x45\xF7\x64\x48\x89\x95\xA0\x00\x00\x00\x4C\x89\xBD\xB0"
    "\x00\x00\x00\x48\xC7\x85\xB8\x00\x00\x00\x0C\x00\x00\x00\x48\xC7\x85\xD0"
    "\x00\x00\x00\x08\x00\x00\x00\x0F\x11\x85\xD8\x00\x00\x00\x88\x45\xF8\x0F"
    "\x11\x85\xE8\x00\x00\x00\xC7\x45\xC8\x4E\x74\x41\x6C\x0F\x11\x85\xF8\x00"
    "\x00\x00\xC7\x45\xCC\x65\x72\x74\x54\x0F\x11\x85\x08\x01\x00\x00\xC7\x45"
    "\xD0\x68\x72\x65\x61\x0F\x11\x85\x18\x01\x00\x00\x66\xC7\x45\xD4\x64\x00"
    "\x4C\x89\x65\x38\x4C\x89\x65\x40\x45\x39\x65\x04\x74\x44\xF6\x41\x50\x02"
    "\x74\x3E\x48\x8D\x54\x24\x48\x48\xC7\x85\xE0\x00\x00\x00\x09\x00\x00\x00"
    "\x48\x89\x95\xD8\x00\x00\x00\x48\x8D\x95\x88\x00\x00\x00\x48\x89\x95\xE8"
    "\x00\x00\x00\x48\x8D\x95\x98\x00\x00\x00\x48\x89\x95\xF0\x00\x00\x00\x48"
    "\xC7\x85\xF8\x00\x00\x00\x02\x00\x00\x00\x48\x8B\x79\x18\x32\xD2\x48\x83"
    "\xC7\x10\x48\x89\xB4\x24\xD8\x02\x00\x00\x4C\x89\xB4\x24\xC0\x02\x00\x00"
    "\x48\x89\xBD\x18\x02\x00\x00\x4C\x8B\x1F\x4C\x3B\xDF\x0F\x84\x0A\x02\x00"
    "\x00\x48\x8B\xC7\x66\x66\x0F\x1F\x84\x00\x00\x00\x00\x00\x49\x8B\x73\x60"
    "\x4D\x8D\x33\x4D\x8B\x1B\x32\xD2\x4C\x89\x9D\x80\x00\x00\x00\x49\x8B\xFC"
    "\x45\x0F\xB7\x5E\x58\x66\x41\xD1\xEB\x4D\x85\xFF\x0F\x84\xAA\x01\x00\x00"
    "\x4C\x8D\x95\xB0\x00\x00\x00\x90\x4D\x39\x62\x20\x74\x4D\x41\x0F\xB7\xC3"
    "\x49\x3B\x42\x08\x75\x43\x45\x0F\xB7\xCC\x66\x45\x3B\xE3\x73\x33\x49\x8B"
    "\x1A\x0F\x1F\x00\x45\x0F\xB7\xC1\x42\x0F\xB7\x14\x46\x8D\x42\x9F\x66\x83"
    "\xF8\x19\x8D\x4A\xE0\x41\x0F\xBE\x04\x18\x66\x0F\x47\xCA\x0F\xB7\xC9\x3B"
    "\xC8\x75\x0A\x66\x41\xFF\xC1\x66\x45\x3B\xCB\x72\xD3\x66\x45\x3B\xCB\x74"
    "\x1F\x48\xFF\xC7\x4C\x8D\x95\xB0\x00\x00\x00\x32\xD2\x48\x8D\x04\xBF\x4D"
    "\x39\x24\xC2\x4D\x8D\x14\xC2\x75\x93\xE9\x29\x01\x00\x00\x32\xD2\x4D\x85"
    "\xD2\x0F\x84\x1E\x01\x00\x00\x49\x8B\x76\x30\x49\x8B\x4A\x20\x48\x63\x46"
    "\x3C\x8B\x84\x30\x88\x00\x00\x00\x48\x03\xC6\x48\x89\x45\x78\x44\x8B\x70"
    "\x20\x44\x8B\x78\x24\x4C\x03\xF6\x44\x8B\x68\x18\x4C\x03\xFE\x0F\x1F\x80"
    "\x00\x00\x00\x00\x45\x85\xED\x0F\x84\xA7\x00\x00\x00\x45\x8B\x1E\x4D\x8B"
    "\xCC\x4C\x03\xDE\x4C\x8B\xC1\x48\x85\xC9\x74\x7F\x49\x8B\x5A\x10\x41\x0F"
    "\xB6\x3B\x4A\x8B\x14\xCB\x0F\xB6\x0A\x40\x3A\xCF\x75\x16\x49\x8B\xC3\x49"
    "\x2B\xD3\x84\xC9\x74\x1A\x0F\xB6\x4C\x02\x01\x48\xFF\xC0\x3A\x08\x74\xF0"
    "\x4D\x8B\x42\x20\x49\xFF\xC1\x4D\x3B\xC8\x72\xD2\xEB\x47\x49\x8B\x4A\x20"
    "\x49\x8B\x52\x18\x4C\x8D\x41\xFF\x4E\x8B\x1C\xCA\x4D\x3B\xC8\x73\x12\x48"
    "\x8B\x44\xCB\xF8\x4A\x89\x04\xCB\x48\x8B\x44\xCA\xF8\x4A\x89\x04\xCA\x4D"
    "\x89\x42\x20\x4D\x85\xDB\x74\x17\x48\x8B\x45\x78\x41\x0F\xB7\x17\x8B\x48"
    "\x1C\x48\x03\xCE\x8B\x04\x91\x48\x03\xC6\x49\x89\x03\x49\x83\xC6\x04\x49"
    "\x83\xC7\x02\x41\xFF\xCD\x49\x8B\xC8\x4D\x85\xC0\x0F\x85\x50\xFF\xFF\xFF"
    "\x4C\x8B\xBD\xB0\x00\x00\x00\xB2\x01\x49\x8B\xCC\x4D\x85\xFF\x74\x41\x49"
    "\x8B\xC4\x4C\x39\xA4\x05\xD0\x00\x00\x00\x77\x1B\x48\xFF\xC1\x48\x8D\x04"
    "\x89\x48\x8D\x04\xC5\x00\x00\x00\x00\x4C\x39\xA4\x05\xB0\x00\x00\x00\x75"
    "\xDD\xEB\x19\x32\xD2\x48\x8B\x85\x18\x02\x00\x00\x4C\x8B\x9D\x80\x00\x00"
    "\x00\x4C\x3B\xD8\x0F\x85\x1E\xFE\xFF\xFF\x48\x8B\x85\x10\x02\x00\x00\x4C"
    "\x8B\x45\x58\x4C\x8B\x55\x38\x4C\x8B\xAD\x00\x02\x00\x00\x48\x8B\x4C\x24"
    "\x30\x41\x8B\x5D\x00\x45\x39\x65\x04\x0F\x84\xE0\x00\x00\x00\xF6\x41\x50"
    "\x02\x0F\x84\xD6\x00\x00\x00\x48\x85\xC0\x74\x34\x83\xFB\x02\x7C\x2F\x48"
    "\x8D\x4C\x24\x30\xC7\x44\x24\x30\x5B\x57\x48\x5D\xC7\x44\x24\x34\x20\x41"
    "\x50\x43\xC7\x44\x24\x38\x20\x52\x45\x0A\x44\x88\x64\x24\x3C\xFF\xD0\x48"
    "\x8B\x85\x10\x02\x00\x00\x4C\x8B\x55\x38\x40\x32\xFF\x4D\x85\xD2\x74\x4C"
    "\x4C\x39\x65\x40\x74\x46\x49\x8B\x55\x20\x45\x33\xC9\x4D\x8B\xC5\x4C\x89"
    "\x64\x24\x20\x48\xC7\xC1\xFE\xFF\xFF\xFF\x41\xFF\xD2\x85\xC0\x78\x1A\x48"
    "\xC7\xC1\xFE\xFF\xFF\xFF\x40\xB7\x01\xFF\x55\x40\x85\xC0\xB9\x04\x00\x00"
    "\x00\x41\x0F\x49\xCC\xEB\x02\xB1\x02\x84\xC9\x74\x42\x48\x8B\x85\x10\x02"
    "\x00\x00\xEB\x02\xB1\x01\x48\x85\xC0\x74\x32\x83\xFB\x01\x7C\x2D\x80\xC1"
    "\x30\xC7\x44\x24\x30\x5B\x57\x48\x5D\x88\x4C\x24\x3C\x48\x8D\x4C\x24\x30"
    "\xC7\x44\x24\x34\x20\x41\x50\x43\xC7\x44\x24\x38\x20\x45\x52\x52\x66\xC7"
    "\x44\x24\x3D\x0A\x00\xFF\xD0\x48\x8B\x45\x30\x40\x84\xFF\x49\x0F\x45\xC4"
    "\xE9\x8A\x02\x00\x00\x84\xD2\x75\x35\x48\x85\xC0\x0F\x84\x79\x02\x00\x00"
    "\x83\xFB\x01\x0F\x8C\x70\x02\x00\x00\x48\x8D\x4C\x24\x30\xC7\x44\x24\x30"
    "\x5B\x57\x48\x5D\xC7\x44\x24\x34\x20\x45\x58\x50\x66\xC7\x44\x24\x38\x0A"
    "\x00\xFF\xD0\xE9\x4D\x02\x00\x00\x48\x8D\x95\x08\x02\x00\x00\xC7\x44\x24"
    "\x58\x49\x6E\x6A\x65\xB9\x01\x00\x00\x00\xC7\x44\x24\x5C\x63\x74\x49\x6E"
    "\x66\xC7\x44\x24\x60\x69\x74\x41\x8B\xF4\x44\x88\x64\x24\x62\x41\x8B\xFC"
    "\x41\xFF\xD0\x83\xFB\x02\x7C\x20\x48\x8D\x4C\x24\x30\xC7\x44\x24\x30\x5B"
    "\x57\x48\x5D\xC7\x44\x24\x34\x20\x4C\x4C\x0A\x40\x88\x74\x24\x38\xFF\x95"
    "\x10\x02\x00\x00\x48\x8B\x45\x60\x49\x8D\x4D\x28\xFF\xD0\x4C\x8B\xF0\x48"
    "\x85\xC0\x0F\x84\xC9\x00\x00\x00\x83\xFB\x02\x7C\x22\x48\x8D\x4C\x24\x30"
    "\xC7\x44\x24\x30\x5B\x57\x48\x5D\xC7\x44\x24\x34\x20\x47\x50\x41\x66\xC7"
    "\x44\x24\x38\x0A\x00\xFF\x95\x10\x02\x00\x00\x48\x8B\x45\x68\x48\x8D\x54"
    "\x24\x58\x49\x8B\xCE\xFF\xD0\x4C\x8B\xF8\x48\x85\xC0\x74\x77\x83\xFB\x02"
    "\x7C\x62\x48\x8D\x4C\x24\x30\xC7\x44\x24\x30\x5B\x57\x48\x5D\xC7\x44\x24"
    "\x34\x20\x49\x49\x0A\x40\x88\x74\x24\x38\xFF\x95\x10\x02\x00\x00\x49\x8B"
    "\xCD\x41\xBC\x01\x00\x00\x00\x41\xFF\xD7\x85\xC0\xC7\x44\x24\x30\x5B\x57"
    "\x48\x5D\x8B\xF0\xC7\x44\x24\x34\x20\x49\x49\x3A\x0F\x95\xC0\xC6\x44\x24"
    "\x38\x20\x04\x30\x66\xC7\x44\x24\x3A\x0A\x00\x48\x8D\x4C\x24\x30\x88\x44"
    "\x24\x39\xFF\x95\x10\x02\x00\x00\xEB\x15\x49\x8B\xCD\x41\xBC\x01\x00\x00"
    "\x00\x41\xFF\xD7\x8B\xF0\xEB\x05\xFF\x55\x48\x8B\xF8\x49\x8B\xCE\xFF\x55"
    "\x70\x85\xF6\x0F\x85\x0F\x01\x00\x00\xEB\x05\xFF\x55\x48\x8B\xF8\x49\x8B"
    "\x4D\x18\x48\x85\xC9\x74\x03\xFF\x55\x50\x49\x8B\x4D\x10\xFF\x55\x50\x45"
    "\x85\xE4\x0F\x85\xEC\x00\x00\x00\x83\xFB\x01\x0F\x8C\xE3\x00\x00\x00\x8B"
    "\xCF\xC7\x44\x24\x30\x5B\x57\x48\x5D\x83\xE1\x0F\xC7\x44\x24\x34\x20\x45"
    "\x52\x52\x83\xF9\x0A\x66\xC7\x44\x24\x38\x3A\x20\xBA\x30\x00\x00\x00\x66"
    "\xC7\x44\x24\x42\x0A\x00\x41\xB8\x37\x00\x00\x00\x8B\xC2\x41\x0F\x43\xC0"
    "\xC1\xEF\x04\x02\xC1\x8B\xCF\x83\xE1\x0F\x88\x44\x24\x41\x83\xF9\x0A\x8B"
    "\xC2\x41\x0F\x43\xC0\xC1\xEF\x04\x02\xC1\x8B\xCF\x83\xE1\x0F\x88\x44\x24"
    "\x40\x83\xF9\x0A\x8B\xC2\x41\x0F\x43\xC0\xC1\xEF\x04\x02\xC1\x8B\xCF\x83"
    "\xE1\x0F\x88\x44\x24\x3F\x83\xF9\x0A\x8B\xC2\x41\x0F\x43\xC0\xC1\xEF\x04"
    "\x02\xC1\x8B\xCF\x83\xE1\x0F\x88\x44\x24\x3E\x83\xF9\x0A\x8B\xC2\x41\x0F"
    "\x43\xC0\xC1\xEF\x04\x02\xC1\x8B\xCF\x83\xE1\x0F\x88\x44\x24\x3D\x83\xF9"
    "\x0A\x8B\xC2\x41\x0F\x43\xC0\xC1\xEF\x04\x02\xC1\x8B\xCF\x83\xE1\x0F\x88"
    "\x44\x24\x3C\x83\xF9\x0A\x8B\xC2\x41\x0F\x43\xC0\xC1\xEF\x04\x02\xC1\x48"
    "\x8D\x4C\x24\x30\x83\xFF\x0A\x88\x44\x24\x3B\x41\x0F\x43\xD0\x40\x02\xD7"
    "\x88\x54\x24\x3A\xFF\x95\x10\x02\x00\x00\x8B\x8D\x08\x02\x00\x00\x33\xD2"
    "\xFF\x55\x58\x48\x8B\x45\x30\x4C\x8B\xB4\x24\xC0\x02\x00\x00\x48\x8B\xB4"
    "\x24\xD8\x02\x00\x00\x48\x8B\xBC\x24\xD0\x02\x00\x00\x4C\x8B\xA4\x24\xC8"
    "\x02\x00\x00\x48\x8B\x9C\x24\xE0\x02\x00\x00\x4C\x8B\xBC\x24\xB8\x02\x00"
    "\x00\x48\x81\xC4\xE8\x02\x00\x00\x41\x5D\x5D\xC3";

constexpr size_t x64ShellcodeSize = sizeof(x64Shellcode) - 1;

#define PRE_ARM64SHELLCODE_VIRTUAL_FREE                       \
    "\xfd\x7b\xbf\xa9" /* stp     fp, lr, [sp, #-0x10]!    */ \
    "\xfd\x03\x00\x91" /* mov     fp, sp                   */ \
    "\x0a\x00\x00\x94" /* bl      $+#0x28                  */ \
    "\xe3\x03\x00\xaa" /* mov     x3, x0                   */ \
    "\xc3\x00\x00\xb4" /* cbz     x3, $+#0x18              */ \
    "\x00\x00\x00\x90" /* adrp    x0, $<page>              */ \
    "\xfd\x7b\xc1\xa8" /* ldp     fp, lr, [sp], #0x10      */ \
    "\x02\x00\x90\x52" /* mov     w2, #0x8000              */ \
    "\x01\x00\x80\xd2" /* mov     x1, #0                   */ \
    "\x60\x00\x1f\xd6" /* br      x3                       */ \
    "\xfd\x7b\xc1\xa8" /* ldp     fp, lr, [sp], #0x10      */ \
    "\xc0\x03\x5f\xd6" /* ret                              */

// The ARM64 InjectShellcode function from the project in the inject_shellcode
// subfolder.
const BYTE arm64Shellcode[] = PRE_ARM64SHELLCODE_VIRTUAL_FREE
    "\xE8\x03\x12\xAA\x0B\x31\x40\xF9\x68\x0D\x40\xF9\x68\x00\x00\xB5\x00\x00"
    "\x80\xD2\xC0\x03\x5F\xD6\xF3\x53\xBB\xA9\xF5\x5B\x01\xA9\xF7\x63\x02\xA9"
    "\xF9\x6B\x03\xA9\xFB\x23\x00\xF9\xFF\x83\x0A\xD1\xFD\x7B\x00\xA9\xFD\x03"
    "\x00\x91\xF6\x03\x00\xAA\xA8\x3F\x00\x58\xE8\x8B\x00\xF9\xC8\x85\x88\x52"
    "\x88\x89\xA9\x72\xE8\x1B\x01\xB9\x48\x3F\x00\x58\xE8\x5B\x00\xF9\x28\x4C"
    "\x8E\x52\x28\xEF\xAA\x72\xE8\xBB\x00\xB9\xFF\xF3\x02\x39\xC8\x3E\x00\x58"
    "\xE8\x53\x00\xF9\x88\x8C\x8C\x52\x48\xAE\xAC\x72\xE8\xAB\x00\xB9\x68\x6E"
    "\x8E\x52\xE8\x5B\x01\x79\xFF\xBB\x02\x39\x08\x3E\x00\x58\xE8\x73\x00\xF9"
    "\x28\x4C\x8E\x52\x28\x0F\xA0\x72\xE8\xEB\x00\xB9\xA8\x3D\x00\x58\xE8\x7B"
    "\x00\xF9\x48\xAE\x8C\x52\xA8\x0C\xA0\x72\xE8\xFB\x00\xB9\x48\x3D\x00\x58"
    "\xE8\x63\x00\xF9\x48\x4E\x8E\x52\xE8\x4D\xAE\x72\xE8\xCB\x00\xB9\xFF\x33"
    "\x03\x39\xD0\x39\x00\x9C\xF0\x4B\x80\x3D\xE8\x2C\x88\x52\xE8\x63\x02\x79"
    "\xFF\xCB\x04\x39\x28\x3C\x00\x58\xE8\x83\x00\xF9\x88\x8C\x8D\x52\xA8\x0C"
    "\xA0\x72\xE8\x0B\x01\xB9\x10\x39\x00\x9C\xF0\x53\x80\x3D\x88\xAC\x8C\x52"
    "\xE8\xA3\x02\x79\xFF\x4B\x05\x39\xE9\xC3\x02\x91\xE8\x83\x02\x91\xF1\x63"
    "\x08\x91\x29\x22\x00\xA9\xE9\x83\x03\x91\xE8\xC3\x03\x91\xF1\xA3\x08\x91"
    "\x29\x22\x00\xA9\xE9\x03\x03\x91\xE8\x83\x04\x91\xF1\xE3\x08\x91\x29\x22"
    "\x00\xA9\xE9\x03\x04\x91\xE8\x03\x05\x91\xF1\x23\x09\x91\x29\x22\x00\xA9"
    "\xFF\xFF\x06\xA9\xFF\x3F\x00\xF9\x00\x00\x80\xD2\x0E\x00\x80\xD2\xFF\xFF"
    "\x02\xA9\x0C\x00\x80\xD2\xFF\xFF\x05\xA9\xE9\xA3\x01\x91\xE8\xC3\x01\x91"
    "\xF1\x63\x09\x91\x29\x22\x00\xA9\xE9\xE3\x01\x91\xE8\xC3\x00\x91\xF1\xA3"
    "\x09\x91\x29\x22\x00\xA9\xE9\x43\x01\x91\xE8\xA3\x00\x91\xF1\xE3\x09\x91"
    "\x29\x22\x00\xA9\xE9\x63\x01\x91\xE8\x83\x01\x91\xF1\x23\x0A\x91\x29\x22"
    "\x00\xA9\xE9\x43\x04\x91\x88\x01\x80\xD2\xE9\x23\x1A\xA9\xE9\x63\x08\x91"
    "\xE8\x63\x09\x91\xE9\x23\x1B\xA9\x08\x01\x80\xD2\x10\xE4\x00\x4F\xFF\x43"
    "\x06\x39\xE8\xE3\x00\xF9\xE8\x23\x07\x91\xE9\x03\x06\x91\xFF\xFF\x04\xA9"
    "\x10\x41\x00\xAD\xEA\x23\x01\x91\x10\x41\x01\xAD\x0F\x00\x80\xD2\x10\x11"
    "\x80\x3D\x08\x34\x00\x58\xE8\x4B\x00\xF9\x88\x09\x80\x52\xE8\x63\x02\x39"
    "\xC8\x33\x00\x58\xE8\x6B\x00\xF9\x08\x4D\x8E\x52\xA8\x2C\xAC\x72\xE8\xDB"
    "\x00\xB9\x88\x0C\x80\x52\xE8\xBB\x01\x79\xE8\x43\x03\x91\xE9\x23\x16\xA9"
    "\xE9\xE3\x00\x91\x10\x30\x00\x9C\xEA\x27\x17\xA9\xC9\x06\x40\xB9\xF0\x63"
    "\x80\x3D\x08\x00\x80\xD2\xFF\x1F\x00\xF9\x69\x01\x00\x34\x69\x51\x40\xB9"
    "\x29\x01\x08\x36\xEA\x43\x02\x91\x29\x01\x80\xD2\xEA\xA7\x1C\xA9\xE9\xC3"
    "\x05\x91\xEA\x83\x05\x91\xEA\xA7\x1D\xA9\x49\x00\x80\xD2\xE9\xF7\x00\xF9"
    "\x69\x0D\x40\xF9\x0A\x00\x80\x52\x2D\x41\x00\x91\xA9\x01\x40\xF9\x3F\x01"
    "\x0D\xEB\x00\x10\x00\x54\xEC\xD3\x40\xF9\x08\x05\x80\xD2\xE5\x03\x09\xAA"
    "\x29\x01\x40\xF9\xA3\xB0\x40\x79\x01\x00\x80\xD2\xAA\x30\x40\xF9\x02\x00"
    "\x80\xD2\x6E\x40\x01\x53\xAC\x04\x00\xB4\xE3\x83\x06\x91\xEE\x03\x0E\xAA"
    "\xF5\xF3\x9F\x52\x13\xFC\x9F\x52\xE7\x83\x06\x91\x6F\x10\x40\xF9\x0F\x03"
    "\x00\xB4\x6F\x04\x40\xF9\xDF\x01\x0F\xEB\xA1\x02\x00\x54\x0F\x00\x80\x52"
    "\x2E\x02\x00\x34\x74\x00\x40\xF9\xEF\x03\x0F\xAA\x46\x79\x6F\x78\xC4\x00"
    "\x15\x0B\x80\x3C\x00\x53\xC4\x00\x13\x0B\x1F\x64\x00\x71\x84\x3C\x00\x53"
    "\xC4\x80\x84\x1A\x86\x6A\xEF\x38\x9F\x00\x06\x6B\xA1\x00\x00\x54\xEF\x05"
    "\x00\x11\xEF\x3D\x00\x53\xFF\x01\x0E\x6B\x43\xFE\xFF\x54\xFF\x01\x0E\x6B"
    "\xC0\x00\x00\x54\x42\x04\x00\x91\x43\x1C\x08\x9B\x6F\x00\x40\xF9\x8F\xFC"
    "\xFF\xB5\x02\x00\x00\x14\xE1\x03\x03\xAA\x0A\x00\x80\x52\x41\x09\x00\xB4"
    "\xA3\x18\x40\xF9\x62\x3C\x40\xB9\x62\xC0\x22\x8B\x42\x88\x40\xB9\x75\x40"
    "\x22\x8B\xAE\x0A\x44\x29\x73\x40\x2E\x8B\x2E\x10\x40\xF9\x6A\x40\x22\x8B"
    "\xA2\x1A\x40\xB9\x2E\x06\x00\xB4\xE2\x05\x00\x34\x6F\x46\x40\xB8\x64\x40"
    "\x2F\x8B\x0F\x00\x80\xD2\x0E\x05\x00\xB4\x34\x08\x40\xF9\x80\x00\xC0\x39"
    "\xE6\x03\x14\xAA\xC5\x84\x40\xF8\xAC\x00\xC0\x39\x9F\x01\x00\x6B\x21\x01"
    "\x00\x54\xEE\x03\x04\xAA\xA5\x00\x04\xCB\x6C\x01\x00\x34\xCE\x05\x00\x91"
    "\xCC\x69\xE5\x38\xC7\x01\xC0\x39\x9F\x01\x07\x6B\x60\xFF\xFF\x54\x2E\x10"
    "\x40\xF9\xEF\x05\x00\x91\xFF\x01\x0E\xEB\x23\xFE\xFF\x54\x14\x00\x00\x14"
    "\x20\xB0\x41\xA9\x8E\x05\x00\xD1\x06\x78\x6F\xF8\xFF\x01\x0E\xEB\xE2\x00"
    "\x00\x54\x84\x0E\x0C\x8B\x84\x80\x5F\xF8\x84\x7A\x2F\xF8\x04\x0C\x0C\x8B"
    "\x84\x80\x5F\xF8\x04\x78\x2F\xF8\x2E\x10\x00\xF9\xE6\x00\x00\xB4\x4F\x01"
    "\x40\x79\xA4\x1E\x40\xB9\x8F\x08\x0F\x8B\xEF\x69\x63\xB8\x6F\x40\x2F\x8B"
    "\xCF\x00\x00\xF9\x4A\x09\x00\x91\x42\x04\x00\x51\x4E\xFA\xFF\xB5\xEC\xD3"
    "\x40\xF9\x2A\x00\x80\x52\x01\x00\x80\xD2\xCC\x01\x00\xB4\x03\x00\x80\xD2"
    "\xE2\x03\x07\x91\xEE\x83\x06\x91\x63\x68\x62\xF8\xC3\x00\x00\xB5\x21\x04"
    "\x00\x91\x23\x7C\x08\x9B\x6F\x68\x6E\xF8\x6F\xFF\xFF\xB5\x04\x00\x00\x14"
    "\x0A\x00\x80\x52\x3F\x01\x0D\xEB\x01\xF1\xFF\x54\xEE\x83\x42\xA9\xEC\x33"
    "\x40\xF9\xE8\x27\x40\xF9\xEF\x1F\x40\xF9\xD3\x26\x40\x29\xA9\x07\x00\x34"
    "\x69\x51\x40\xB9\x69\x07\x08\x36\xDF\x01\x00\xF1\x6A\x1A\x42\x7A\x55\x1F"
    "\x00\x58\x6B\x01\x00\x54\x08\x44\x8A\x52\xA8\x48\xA1\x72\xF5\x0B\x00\xF9"
    "\xE0\x43\x00\x91\xE8\x1B\x00\xB9\xFF\x73\x00\x39\xC0\x01\x3F\xD6\xEE\x83"
    "\x42\xA9\xE8\x27\x40\xF9\xEF\x1F\x40\xF9\x14\x00\x80\x52\x28\x03\x00\xB4"
    "\x0F\x03\x00\xB4\xC1\x12\x40\xF9\x04\x00\x80\xD2\x03\x00\x80\xD2\xE2\x03"
    "\x16\xAA\x20\x00\x80\x92\x00\x01\x3F\xD6\x60\x01\xF8\x37\xE8\x1F\x40\xF9"
    "\x20\x00\x80\x92\x34\x00\x80\x52\x00\x01\x3F\xD6\x88\x00\x80\x52\x1F\x00"
    "\x00\x71\xE9\xA3\x88\x1A\x08\x7C\x1F\x13\x08\x01\x1E\x12\x03\x00\x00\x14"
    "\x49\x00\x80\x52\x48\x00\x80\x52\xE0\x1B\x40\xF9\x49\x02\x00\x34\xEE\x17"
    "\x40\xF9\x02\x00\x00\x14\x28\x00\x80\x52\xDF\x01\x00\xF1\x6A\x1A\x41\x7A"
    "\x8B\x01\x00\x54\x08\xC1\x00\x11\xF5\x0B\x00\xF9\xE8\x73\x00\x39\x09\xA4"
    "\x88\x52\x49\x4A\xAA\x72\x48\x01\x80\x52\xE9\x1B\x00\xB9\xE0\x43\x00\x91"
    "\xE8\xD3\x01\x78\xC0\x01\x3F\xD6\xE0\x1B\x40\xF9\x9F\x02\x00\x71\xE0\x13"
    "\x80\x9A\x9C\x00\x00\x14\x6A\x01\x00\x35\xDF\x01\x00\xF1\x6A\x1A\x41\x7A"
    "\x0B\x13\x00\x54\x08\x18\x00\x58\xE8\x0B\x00\xF9\x48\x01\x80\x52\xE0\x43"
    "\x00\x91\xE8\x33\x00\x79\xC0\x01\x3F\xD6\x90\x00\x00\x14\x68\x17\x00\x58"
    "\xFF\x2B\x02\x39\xE8\x43\x00\xF9\x28\x8D\x8E\x52\xE1\x03\x01\x91\xE8\x13"
    "\x01\x79\x20\x00\x80\x52\x1A\x00\x80\x52\x18\x00\x80\x52\x17\x00\x80\x52"
    "\x80\x01\x3F\xD6\x7F\x0A\x00\x71\xEB\x00\x00\x54\x08\x16\x00\x58\xFF\x63"
    "\x00\x39\xE8\x0B\x00\xF9\xE8\x17\x40\xF9\xE0\x43\x00\x91\x00\x01\x3F\xD6"
    "\xE8\x37\x40\xF9\xC0\xA2\x00\x91\x00\x01\x3F\xD6\x55\x01\x80\x52\x14\x06"
    "\x80\x52\xF9\x03\x00\xAA\x99\x06\x00\xB4\x7F\x0A\x00\x71\xEB\x00\x00\x54"
    "\x68\x14\x00\x58\xF5\x33\x00\x79\xE8\x0B\x00\xF9\xE8\x17\x40\xF9\xE0\x43"
    "\x00\x91\x00\x01\x3F\xD6\xE8\x3B\x40\xF9\xE1\x03\x02\x91\xE0\x03\x19\xAA"
    "\x00\x01\x3F\xD6\xFB\x03\x00\xAA\xDB\x03\x00\xB4\x7F\x0A\x00\x71\xEB\x02"
    "\x00\x54\xE8\x12\x00\x58\xFF\x63\x00\x39\xE8\x0B\x00\xF9\xE8\x17\x40\xF9"
    "\xE0\x43\x00\x91\x00\x01\x3F\xD6\xE0\x03\x16\xAA\x3A\x00\x80\x52\x60\x03"
    "\x3F\xD6\xF5\x37\x00\x79\xE8\x11\x00\x58\xE8\x0B\x00\xF9\xF8\x03\x00\x2A"
    "\x08\x04\x80\x52\x1F\x03\x00\x71\xE8\x63\x00\x39\x88\x06\x94\x1A\xE8\x67"
    "\x00\x39\xE8\x17\x40\xF9\xE0\x43\x00\x91\x00\x01\x3F\xD6\x09\x00\x00\x14"
    "\xE0\x03\x16\xAA\x3A\x00\x80\x52\x60\x03\x3F\xD6\xF8\x03\x00\x2A\x04\x00"
    "\x00\x14\xE8\x2B\x40\xF9\x00\x01\x3F\xD6\xF7\x03\x00\x2A\xE8\x3F\x40\xF9"
    "\xE0\x03\x19\xAA\x00\x01\x3F\xD6\x18\x08\x00\x35\x04\x00\x00\x14\xE8\x2B"
    "\x40\xF9\x00\x01\x3F\xD6\xF7\x03\x00\x2A\xC0\x0E\x40\xF9\x60\x00\x00\xB4"
    "\xE8\x2F\x40\xF9\x00\x01\x3F\xD6\xC0\x0A\x40\xF9\xE8\x2F\x40\xF9\x00\x01"
    "\x3F\xD6\x9A\x06\x00\x35\x7F\x06\x00\x71\x4B\x06\x00\x54\x68\x0D\x00\x58"
    "\xF5\x47\x00\x79\xE8\x0B\x00\xF9\xE9\x0E\x00\x12\x48\x07\x84\x52\xE8\x33"
    "\x00\x79\x3F\x29\x00\x71\xEA\x06\x80\x52\x48\x21\x94\x1A\x08\x81\x29\x0B"
    "\xE9\x1E\x04\x53\x3F\x29\x00\x71\xE8\x87\x00\x39\x48\x21\x94\x1A\x08\x81"
    "\x29\x0B\xE9\x2E\x08\x53\x3F\x29\x00\x71\xE8\x83\x00\x39\x48\x21\x94\x1A"
    "\x08\x81\x29\x0B\xE9\x3E\x0C\x53\x3F\x29\x00\x71\xE8\x7F\x00\x39\x48\x21"
    "\x94\x1A\x08\x81\x29\x0B\xE9\x4E\x10\x53\x3F\x29\x00\x71\xE8\x7B\x00\x39"
    "\x48\x21\x94\x1A\x08\x81\x29\x0B\xE9\x5E\x14\x53\x3F\x29\x00\x71\xE8\x77"
    "\x00\x39\x48\x21\x94\x1A\x08\x81\x29\x0B\xE9\x6E\x18\x53\x3F\x29\x00\x71"
    "\xE8\x73\x00\x39\x48\x21\x94\x1A\x08\x81\x29\x0B\xE9\x7E\x1C\x53\x3F\x29"
    "\x00\x71\xE8\x6F\x00\x39\x48\x21\x94\x1A\x08\x81\x29\x0B\xE0\x43\x00\x91"
    "\xE8\x6B\x00\x39\xE8\x17\x40\xF9\x00\x01\x3F\xD6\xE0\x43\x40\xB9\x01\x00"
    "\x80\xD2\xE8\x33\x40\xF9\x00\x01\x3F\xD6\xE0\x1B\x40\xF9\xFD\x7B\x40\xA9"
    "\xFF\x83\x0A\x91\xFB\x23\x40\xF9\xF9\x6B\x43\xA9\xF7\x63\x42\xA9\xF5\x5B"
    "\x41\xA9\xF3\x53\xC5\xA8\xC0\x03\x5F\xD6\x1F\x20\x03\xD5\x4F\x75\x74\x70"
    "\x75\x74\x44\x65\x62\x75\x67\x53\x74\x72\x69\x6E\x53\x65\x74\x54\x68\x72"
    "\x65\x61\x64\x45\x72\x72\x6F\x72\x4D\x6F\x4E\x74\x51\x75\x65\x75\x65\x41"
    "\x70\x63\x54\x68\x72\x65\x61\x64\x4B\x45\x52\x4E\x45\x4C\x33\x32\x4C\x6F"
    "\x61\x64\x4C\x69\x62\x72\x47\x65\x74\x50\x72\x6F\x63\x41\x46\x72\x65\x65"
    "\x4C\x69\x62\x72\x56\x69\x72\x74\x75\x61\x6C\x46\x47\x65\x74\x4C\x61\x73"
    "\x74\x45\x43\x6C\x6F\x73\x65\x48\x61\x6E\x4E\x54\x44\x4C\x4C\x2E\x44\x4C"
    "\x4E\x74\x41\x6C\x65\x72\x74\x54\x5B\x57\x48\x5D\x20\x41\x50\x43\x5B\x57"
    "\x48\x5D\x20\x45\x58\x50\x49\x6E\x6A\x65\x63\x74\x49\x6E\x5B\x57\x48\x5D"
    "\x20\x4C\x4C\x0A\x5B\x57\x48\x5D\x20\x47\x50\x41\x5B\x57\x48\x5D\x20\x49"
    "\x49\x0A\x5B\x57\x48\x5D\x20\x49\x49\x3A\x5B\x57\x48\x5D\x20\x45\x52\x52";

constexpr size_t arm64ShellcodeSize = sizeof(arm64Shellcode) - 1;

using PPS_APC_ROUTINE = VOID(NTAPI*)(_In_opt_ PVOID ApcArgument1,
                                     _In_opt_ PVOID ApcArgument2,
                                     _In_opt_ PVOID ApcArgument3);

#ifdef _M_IX86
void NtQueueApcThread64(_In_ HANDLE ThreadHandle,
                        _In_ PPS_APC_ROUTINE ApcRoutine,
                        _In_opt_ PVOID ApcArgument1,
                        _In_opt_ PVOID ApcArgument2,
                        _In_opt_ PVOID ApcArgument3) {
    STATIC_INIT_ONCE_TRIVIAL(DWORD64, pNtQueueApcThread, []() {
        auto ntdll = wow64pp::module_handle("ntdll.dll");
        return wow64pp::import(ntdll, "NtQueueApcThread");
    }());

    auto result64 = wow64pp::call_function(
        pNtQueueApcThread, wow64pp::handle_to_uint64(ThreadHandle),
        wow64pp::ptr_to_uint64(ApcRoutine),
        wow64pp::ptr_to_uint64(ApcArgument1),
        wow64pp::ptr_to_uint64(ApcArgument2),
        wow64pp::ptr_to_uint64(ApcArgument3));
    NTSTATUS result = static_cast<NTSTATUS>(result64);
    THROW_IF_NTSTATUS_FAILED(result);
}

using PUSER_THREAD_START_ROUTINE = NTSTATUS(NTAPI*)(_In_ PVOID ThreadParameter);

void NtCreateThreadEx64(_Out_ PHANDLE ThreadHandle,
                        _In_ ACCESS_MASK DesiredAccess,
                        _In_opt_ void* ObjectAttributes,  // PCOBJECT_ATTRIBUTES
                        _In_ HANDLE ProcessHandle,
                        _In_ PUSER_THREAD_START_ROUTINE StartRoutine,
                        _In_opt_ PVOID Argument,
                        _In_ ULONG CreateFlags,  // THREAD_CREATE_FLAGS_*
                        _In_ DWORD64 ZeroBits,
                        _In_ DWORD64 StackSize,
                        _In_ DWORD64 MaximumStackSize,
                        _In_opt_ void* AttributeList) {  // PPS_ATTRIBUTE_LIST
    STATIC_INIT_ONCE_TRIVIAL(DWORD64, pNtCreateThreadEx, []() {
        auto ntdll = wow64pp::module_handle("ntdll.dll");
        return wow64pp::import(ntdll, "NtCreateThreadEx");
    }());

    DWORD64 threadHandle64 = 0;

    auto result64 = wow64pp::call_function(
        pNtCreateThreadEx, wow64pp::ptr_to_uint64(&threadHandle64),
        DesiredAccess, wow64pp::ptr_to_uint64(ObjectAttributes),
        wow64pp::handle_to_uint64(ProcessHandle),
        wow64pp::ptr_to_uint64(StartRoutine), wow64pp::ptr_to_uint64(Argument),
        CreateFlags, ZeroBits, StackSize, MaximumStackSize,
        wow64pp::ptr_to_uint64(AttributeList));
    NTSTATUS result = static_cast<NTSTATUS>(result64);
    THROW_IF_NTSTATUS_FAILED(result);
    *ThreadHandle = reinterpret_cast<HANDLE>(threadHandle64);
}
#endif  // _M_IX86

#ifdef _WIN64
//
// Reference: https://repnz.github.io/posts/apc/wow64-user-apc/
//
ULONG64 EncodeWow64ApcRoutine(ULONG64 ApcRoutine) {
    return (ULONG64)((-(INT64)ApcRoutine) << 2);
}
#endif  // _WIN64

//
// Reference: https://repnz.github.io/posts/apc/user-apc/
//
void MyQueueUserAPC(PPS_APC_ROUTINE pfnAPC,
                    HANDLE hThread,
                    void* data,
                    USHORT targetProcessArch) {
#ifndef _WIN64
    if (targetProcessArch == IMAGE_FILE_MACHINE_AMD64 ||
        targetProcessArch == IMAGE_FILE_MACHINE_ARM64) {
        // WOW64 to x64 native, use heaven's gate.
        //
        // "Microsoft added a validation to prevent a programming error:
        // If you try to queue an APC from a 32 bit process to a 64 bit
        // process and you use a 32 bit address, you'll get this status code:
        // [...] STATUS_INVALID_HANDLE"
        // https://repnz.github.io/posts/apc/wow64-user-apc/
        NtQueueApcThread64(hThread, pfnAPC, data, 0, 0);
        return;
    }
#endif  // _WIN64

    using NtQueueApcThread_t = NTSTATUS(NTAPI*)(
        _In_ HANDLE ThreadHandle, _In_ PPS_APC_ROUTINE ApcRoutine,
        _In_opt_ PVOID ApcArgument1, _In_opt_ PVOID ApcArgument2,
        _In_opt_ PVOID ApcArgument3);

    GET_PROC_ADDRESS_ONCE(NtQueueApcThread_t, pNtQueueApcThread, L"ntdll.dll",
                          "NtQueueApcThread");

    if (!pNtQueueApcThread) {
        throw std::runtime_error("NtQueueApcThread not found");
    }

#ifdef _WIN64
    if (targetProcessArch == IMAGE_FILE_MACHINE_I386) {
        // x64 native to WOW64, encode address.
        pfnAPC = (PPS_APC_ROUTINE)EncodeWow64ApcRoutine((ULONG64)pfnAPC);
    }
#endif  // _WIN64

    THROW_IF_NTSTATUS_FAILED(pNtQueueApcThread(hThread, pfnAPC, data, 0, 0));
}

USHORT GetProcessArch(HANDLE hProcess) {
    using GetProcessInformation_t = BOOL(WINAPI*)(
        HANDLE hProcess, PROCESS_INFORMATION_CLASS ProcessInformationClass,
        LPVOID ProcessInformation, DWORD ProcessInformationSize);

    GET_PROC_ADDRESS_ONCE(GetProcessInformation_t, pGetProcessInformation,
                          L"kernel32.dll", "GetProcessInformation");

    if (pGetProcessInformation) {
        PROCESS_MACHINE_INFORMATION pmi;
        if (pGetProcessInformation(hProcess, ProcessMachineTypeInfo, &pmi,
                                   sizeof(pmi))) {
            return pmi.ProcessMachine;
        }

        THROW_LAST_ERROR_IF(GetLastError() != ERROR_INVALID_PARAMETER);
    }

    // If GetProcessInformation(ProcessMachineTypeInfo) isn't supported, assume
    // only IMAGE_FILE_MACHINE_I386 and IMAGE_FILE_MACHINE_AMD64.

#ifndef _WIN64
    SYSTEM_INFO siSystemInfo;
    GetNativeSystemInfo(&siSystemInfo);
    if (siSystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) {
        // 32-bit machine, only one option.
        return IMAGE_FILE_MACHINE_I386;
    }
#endif  // _WIN64

    BOOL bIsWow64Process;
    if (IsWow64Process(hProcess, &bIsWow64Process) && bIsWow64Process) {
        return IMAGE_FILE_MACHINE_I386;
    }

    return IMAGE_FILE_MACHINE_AMD64;
}

}  // namespace

namespace DllInject {

void DllInject(HANDLE hProcess,
               HANDLE hThreadForAPC,
               HANDLE hSessionManagerProcess,
               HANDLE hSessionMutex,
               bool threadAttachExempt) {
    const BYTE* shellcode;
    size_t shellcodeSize;

    USHORT targetProcessArch = GetProcessArch(hProcess);
    switch (targetProcessArch) {
        case IMAGE_FILE_MACHINE_I386:
            if (hThreadForAPC) {
                // The calling convention is different - three arguments instead
                // of one.
                shellcode = x32APCShellcode;
                shellcodeSize = x32APCShellcodeSize;
            } else {
                shellcode = x32Shellcode;
                shellcodeSize = x32ShellcodeSize;
            }
            break;

        case IMAGE_FILE_MACHINE_AMD64:
            shellcode = x64Shellcode;
            shellcodeSize = x64ShellcodeSize;
            break;

        case IMAGE_FILE_MACHINE_ARM64:
            shellcode = arm64Shellcode;
            shellcodeSize = arm64ShellcodeSize;
            break;

        default:
            throw std::logic_error("Invalid architecture value");
    }

    std::wstring dllPath =
        StorageManager::GetInstance().GetEnginePath(targetProcessArch) /
        L"windhawk.dll";
    size_t dllPathBytes = (dllPath.length() + 1) * sizeof(WCHAR);

    HANDLE hRemoteSessionManagerProcess;
    THROW_IF_WIN32_BOOL_FALSE(DuplicateHandle(
        GetCurrentProcess(), hSessionManagerProcess, hProcess,
        &hRemoteSessionManagerProcess,
        PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE, FALSE, 0));

    auto remoteSessionManagerProcessCleanup =
        wil::scope_exit([hProcess, hRemoteSessionManagerProcess] {
            DuplicateHandle(hProcess, hRemoteSessionManagerProcess, nullptr,
                            nullptr, 0, FALSE, DUPLICATE_CLOSE_SOURCE);
        });

    HANDLE hRemoteSessionMutex = nullptr;
    if (hSessionMutex) {
        THROW_IF_WIN32_BOOL_FALSE(DuplicateHandle(
            GetCurrentProcess(), hSessionMutex, hProcess, &hRemoteSessionMutex,
            PROCESS_QUERY_LIMITED_INFORMATION, FALSE, 0));
    }

    auto remoteSessionMutexCleanup =
        wil::scope_exit([hProcess, hRemoteSessionMutex] {
            if (hRemoteSessionMutex) {
                DuplicateHandle(hProcess, hRemoteSessionMutex, nullptr, nullptr,
                                0, FALSE, DUPLICATE_CLOSE_SOURCE);
            }
        });

    size_t shellcodeDataSize =
        offsetof(LOAD_LIBRARY_REMOTE_DATA, szDllName) + dllPathBytes;
    auto shellcodeDataVector = std::vector<BYTE>(shellcodeDataSize);
    auto shellcodeData =
        reinterpret_cast<LOAD_LIBRARY_REMOTE_DATA*>(shellcodeDataVector.data());

    shellcodeData->nLogVerbosity =
        static_cast<INT32>(Logger::GetInstance().GetVerbosity());
    shellcodeData->bRunningFromAPC = !!hThreadForAPC;
    shellcodeData->bThreadAttachExempt = threadAttachExempt;
    shellcodeData->hSessionManagerProcess = hRemoteSessionManagerProcess;
    shellcodeData->hSessionMutex = hRemoteSessionMutex;
    memcpy(shellcodeData->szDllName, dllPath.c_str(), dllPathBytes);

    size_t shellcodeSizeAligned =
        (shellcodeSize + (sizeof(LONG_PTR) - 1)) & ~(sizeof(LONG_PTR) - 1);

    // Allocate enough memory in the remote process's address space
    // to hold the shellcode and the data struct.
    void* pRemoteCode = VirtualAllocEx(
        hProcess, nullptr, shellcodeSizeAligned + shellcodeDataSize,
        MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    THROW_LAST_ERROR_IF_NULL(pRemoteCode);

    auto remoteCodeCleanup = wil::scope_exit([hProcess, pRemoteCode] {
        VirtualFreeEx(hProcess, pRemoteCode, 0, MEM_RELEASE);
    });

    shellcodeData->pInjectedShellcodeAddress = pRemoteCode;

    // Write our shellcode into the remote process.
    THROW_IF_WIN32_BOOL_FALSE(WriteProcessMemory(
        hProcess, pRemoteCode, shellcode, shellcodeSize, nullptr));

    // Write a copy of our struct to the remote process.
    void* pRemoteData =
        reinterpret_cast<BYTE*>(pRemoteCode) + shellcodeSizeAligned;
    THROW_IF_WIN32_BOOL_FALSE(WriteProcessMemory(
        hProcess, pRemoteData, shellcodeData, shellcodeDataSize, nullptr));

    // Mark shellcode as executable.
    DWORD oldProtect;
    THROW_IF_WIN32_BOOL_FALSE(VirtualProtectEx(
        hProcess, pRemoteCode, shellcodeSize, PAGE_EXECUTE_READ, &oldProtect));

    if (hThreadForAPC) {
        MyQueueUserAPC(reinterpret_cast<PPS_APC_ROUTINE>(pRemoteCode),
                       hThreadForAPC, pRemoteData, targetProcessArch);
    } else {
        DWORD createThreadFlags = 0;

        if (threadAttachExempt) {
            createThreadFlags |=
                Functions::MY_REMOTE_THREAD_THREAD_ATTACH_EXEMPT;
        }

#ifndef _WIN64
        if (targetProcessArch == IMAGE_FILE_MACHINE_AMD64 ||
            targetProcessArch == IMAGE_FILE_MACHINE_ARM64) {
            // WOW64 to x64 native, use heaven's gate.
            wil::unique_process_handle remoteThread;
            NtCreateThreadEx64(
                &remoteThread, THREAD_ALL_ACCESS, nullptr, hProcess,
                reinterpret_cast<PUSER_THREAD_START_ROUTINE>(pRemoteCode),
                pRemoteData, createThreadFlags, 0, 0, 0, nullptr);
        } else
#endif  // _WIN64
        {
            wil::unique_process_handle remoteThread(
                Functions::MyCreateRemoteThread(
                    hProcess,
                    reinterpret_cast<LPTHREAD_START_ROUTINE>(pRemoteCode),
                    pRemoteData, createThreadFlags));
            THROW_LAST_ERROR_IF_NULL(remoteThread);
        }
    }

    remoteSessionManagerProcessCleanup.release();
    remoteSessionMutexCleanup.release();
    remoteCodeCleanup.release();
}

}  // namespace DllInject
